home *** CD-ROM | disk | FTP | other *** search
/ Komputer for Alle 1999 #5 / 1999 CD 5 (black).iso / Delphi3 / install / data.z / SPIN.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-08-05  |  16.8 KB  |  633 lines

  1. unit Spin;
  2.  
  3. interface
  4.  
  5. uses Windows, Classes, StdCtrls, ExtCtrls, Controls, Messages, SysUtils,
  6.   Forms, Graphics, Menus, Buttons;
  7.  
  8. const
  9.   InitRepeatPause = 400;  { pause before repeat timer (ms) }
  10.   RepeatPause     = 100;  { pause before hint window displays (ms)}
  11.  
  12. type
  13.  
  14.   TNumGlyphs = Buttons.TNumGlyphs;
  15.  
  16.   TTimerSpeedButton = class;
  17.  
  18. { TSpinButton }
  19.  
  20.   TSpinButton = class (TWinControl)
  21.   private
  22.     FUpButton: TTimerSpeedButton;
  23.     FDownButton: TTimerSpeedButton;
  24.     FFocusedButton: TTimerSpeedButton;
  25.     FFocusControl: TWinControl;
  26.     FOnUpClick: TNotifyEvent;
  27.     FOnDownClick: TNotifyEvent;
  28.     function CreateButton: TTimerSpeedButton;
  29.     function GetUpGlyph: TBitmap;
  30.     function GetDownGlyph: TBitmap;
  31.     procedure SetUpGlyph(Value: TBitmap);
  32.     procedure SetDownGlyph(Value: TBitmap);
  33.     function GetUpNumGlyphs: TNumGlyphs;
  34.     function GetDownNumGlyphs: TNumGlyphs;
  35.     procedure SetUpNumGlyphs(Value: TNumGlyphs);
  36.     procedure SetDownNumGlyphs(Value: TNumGlyphs);
  37.     procedure BtnClick(Sender: TObject);
  38.     procedure BtnMouseDown (Sender: TObject; Button: TMouseButton;
  39.       Shift: TShiftState; X, Y: Integer);
  40.     procedure SetFocusBtn (Btn: TTimerSpeedButton);
  41.     procedure AdjustSize (var W: Integer; var H: Integer);
  42.     procedure WMSize(var Message: TWMSize);  message WM_SIZE;
  43.     procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
  44.     procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
  45.     procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
  46.   protected
  47.     procedure Loaded; override;
  48.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  49.     procedure Notification(AComponent: TComponent;
  50.       Operation: TOperation); override;
  51.   public
  52.     constructor Create(AOwner: TComponent); override;
  53.     procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  54.   published
  55.     property Align;
  56.     property Ctl3D;
  57.     property DownGlyph: TBitmap read GetDownGlyph write SetDownGlyph;
  58.     property DownNumGlyphs: TNumGlyphs read GetDownNumGlyphs write SetDownNumGlyphs default 1;
  59.     property DragCursor;
  60.     property DragMode;
  61.     property Enabled;
  62.     property FocusControl: TWinControl read FFocusControl write FFocusControl;
  63.     property ParentCtl3D;
  64.     property ParentShowHint;
  65.     property PopupMenu;
  66.     property ShowHint;
  67.     property TabOrder;
  68.     property TabStop;
  69.     property UpGlyph: TBitmap read GetUpGlyph write SetUpGlyph;
  70.     property UpNumGlyphs: TNumGlyphs read GetUpNumGlyphs write SetUpNumGlyphs default 1;
  71.     property Visible;
  72.     property OnDownClick: TNotifyEvent read FOnDownClick write FOnDownClick;
  73.     property OnDragDrop;
  74.     property OnDragOver;
  75.     property OnEndDrag;
  76.     property OnEnter;
  77.     property OnExit;
  78.     property OnStartDrag;
  79.     property OnUpClick: TNotifyEvent read FOnUpClick write FOnUpClick;
  80.   end;
  81.  
  82. { TSpinEdit }
  83.  
  84.   TSpinEdit = class(TCustomEdit)
  85.   private
  86.     FMinValue: LongInt;
  87.     FMaxValue: LongInt;
  88.     FIncrement: LongInt;
  89.     FButton: TSpinButton;
  90.     FEditorEnabled: Boolean;
  91.     function GetMinHeight: Integer;
  92.     function GetValue: LongInt;
  93.     function CheckValue (NewValue: LongInt): LongInt;
  94.     procedure SetValue (NewValue: LongInt);
  95.     procedure SetEditRect;
  96.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  97.     procedure CMEnter(var Message: TCMGotFocus); message CM_ENTER;
  98.     procedure CMExit(var Message: TCMExit);   message CM_EXIT;
  99.     procedure WMPaste(var Message: TWMPaste);   message WM_PASTE;
  100.     procedure WMCut(var Message: TWMCut);   message WM_CUT;
  101.   protected
  102.     procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
  103.     function IsValidChar(Key: Char): Boolean; virtual;
  104.     procedure UpClick (Sender: TObject); virtual;
  105.     procedure DownClick (Sender: TObject); virtual;
  106.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  107.     procedure KeyPress(var Key: Char); override;
  108.     procedure CreateParams(var Params: TCreateParams); override;
  109.     procedure CreateWnd; override;
  110.   public
  111.     constructor Create(AOwner: TComponent); override;
  112.     destructor Destroy; override;
  113.     property Button: TSpinButton read FButton;
  114.   published
  115.     property AutoSelect;
  116.     property AutoSize;
  117.     property Color;
  118.     property Ctl3D;
  119.     property DragCursor;
  120.     property DragMode;
  121.     property EditorEnabled: Boolean read FEditorEnabled write FEditorEnabled default True;
  122.     property Enabled;
  123.     property Font;
  124.     property Increment: LongInt read FIncrement write FIncrement default 1;
  125.     property MaxLength;
  126.     property MaxValue: LongInt read FMaxValue write FMaxValue;
  127.     property MinValue: LongInt read FMinValue write FMinValue;
  128.     property ParentColor;
  129.     property ParentCtl3D;
  130.     property ParentFont;
  131.     property ParentShowHint;
  132.     property PopupMenu;
  133.     property ReadOnly;
  134.     property ShowHint;
  135.     property TabOrder;
  136.     property TabStop;
  137.     property Value: LongInt read GetValue write SetValue;
  138.     property Visible;
  139.     property OnChange;
  140.     property OnClick;
  141.     property OnDblClick;
  142.     property OnDragDrop;
  143.     property OnDragOver;
  144.     property OnEndDrag;
  145.     property OnEnter;
  146.     property OnExit;
  147.     property OnKeyDown;
  148.     property OnKeyPress;
  149.     property OnKeyUp;
  150.     property OnMouseDown;
  151.     property OnMouseMove;
  152.     property OnMouseUp;
  153.     property OnStartDrag;
  154.   end;
  155.  
  156. { TTimerSpeedButton }
  157.  
  158.   TTimeBtnState = set of (tbFocusRect, tbAllowTimer);
  159.  
  160.   TTimerSpeedButton = class(TSpeedButton)
  161.   private
  162.     FRepeatTimer: TTimer;
  163.     FTimeBtnState: TTimeBtnState;
  164.     procedure TimerExpired(Sender: TObject);
  165.   protected
  166.     procedure Paint; override;
  167.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  168.       X, Y: Integer); override;
  169.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
  170.       X, Y: Integer); override;
  171.   public
  172.     destructor Destroy; override;
  173.     property TimeBtnState: TTimeBtnState read FTimeBtnState write FTimeBtnState;
  174.   end;
  175.  
  176. implementation
  177.  
  178. {$R SPIN}
  179.  
  180. { TSpinButton }
  181.  
  182. constructor TSpinButton.Create(AOwner: TComponent);
  183. begin
  184.   inherited Create(AOwner);
  185.   ControlStyle := ControlStyle - [csAcceptsControls, csSetCaption] +
  186.     [csFramed, csOpaque];
  187.  
  188.   FUpButton := CreateButton;
  189.   FDownButton := CreateButton;
  190.   UpGlyph := nil;
  191.   DownGlyph := nil;
  192.  
  193.   Width := 20;
  194.   Height := 25;
  195.   FFocusedButton := FUpButton;
  196. end;
  197.  
  198. function TSpinButton.CreateButton: TTimerSpeedButton;
  199. begin
  200.   Result := TTimerSpeedButton.Create (Self);
  201.   Result.OnClick := BtnClick;
  202.   Result.OnMouseDown := BtnMouseDown;
  203.   Result.Visible := True;
  204.   Result.Enabled := True;
  205.   Result.TimeBtnState := [tbAllowTimer];
  206.   Result.Parent := Self;
  207. end;
  208.  
  209. procedure TSpinButton.Notification(AComponent: TComponent;
  210.   Operation: TOperation);
  211. begin
  212.   inherited Notification(AComponent, Operation);
  213.   if (Operation = opRemove) and (AComponent = FFocusControl) then
  214.     FFocusControl := nil;
  215. end;
  216.  
  217. procedure TSpinButton.AdjustSize (var W: Integer; var H: Integer);
  218. begin
  219.   if (FUpButton = nil) or (csLoading in ComponentState) then Exit;
  220.   if W < 15 then W := 15;
  221.   FUpButton.SetBounds (0, 0, W, H div 2);
  222.   FDownButton.SetBounds (0, FUpButton.Height - 1, W, H - FUpButton.Height + 1);
  223. end;
  224.  
  225. procedure TSpinButton.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
  226. var
  227.   W, H: Integer;
  228. begin
  229.   W := AWidth;
  230.   H := AHeight;
  231.   AdjustSize (W, H);
  232.   inherited SetBounds (ALeft, ATop, W, H);
  233. end;
  234.  
  235. procedure TSpinButton.WMSize(var Message: TWMSize);
  236. var
  237.   W, H: Integer;
  238. begin
  239.   inherited;
  240.  
  241.   { check for minimum size }
  242.   W := Width;
  243.   H := Height;
  244.   AdjustSize (W, H);
  245.   if (W <> Width) or (H <> Height) then
  246.     inherited SetBounds(Left, Top, W, H);
  247.   Message.Result := 0;
  248. end;
  249.  
  250. procedure TSpinButton.WMSetFocus(var Message: TWMSetFocus);
  251. begin
  252.   FFocusedButton.TimeBtnState := FFocusedButton.TimeBtnState + [tbFocusRect];
  253.   FFocusedButton.Invalidate;
  254. end;
  255.  
  256. procedure TSpinButton.WMKillFocus(var Message: TWMKillFocus);
  257. begin
  258.   FFocusedButton.TimeBtnState := FFocusedButton.TimeBtnState - [tbFocusRect];
  259.   FFocusedButton.Invalidate;
  260. end;
  261.  
  262. procedure TSpinButton.KeyDown(var Key: Word; Shift: TShiftState);
  263. begin
  264.   case Key of
  265.     VK_UP:
  266.       begin
  267.         SetFocusBtn (FUpButton);
  268.         FUpButton.Click;
  269.       end;
  270.     VK_DOWN:
  271.       begin
  272.         SetFocusBtn (FDownButton);
  273.         FDownButton.Click;
  274.       end;
  275.     VK_SPACE:
  276.       FFocusedButton.Click;
  277.   end;
  278. end;
  279.  
  280. procedure TSpinButton.BtnMouseDown (Sender: TObject; Button: TMouseButton;
  281.   Shift: TShiftState; X, Y: Integer);
  282. begin
  283.   if Button = mbLeft then
  284.   begin
  285.     SetFocusBtn (TTimerSpeedButton (Sender));
  286.     if (FFocusControl <> nil) and FFocusControl.TabStop and 
  287.         FFocusControl.CanFocus and (GetFocus <> FFocusControl.Handle) then
  288.       FFocusControl.SetFocus
  289.     else if TabStop and (GetFocus <> Handle) and CanFocus then
  290.       SetFocus;
  291.   end;
  292. end;
  293.  
  294. procedure TSpinButton.BtnClick(Sender: TObject);
  295. begin
  296.   if Sender = FUpButton then
  297.   begin
  298.     if Assigned(FOnUpClick) then FOnUpClick(Self);
  299.   end
  300.   else
  301.     if Assigned(FOnDownClick) then FOnDownClick(Self);
  302. end;
  303.  
  304. procedure TSpinButton.SetFocusBtn (Btn: TTimerSpeedButton);
  305. begin
  306.   if TabStop and CanFocus and  (Btn <> FFocusedButton) then
  307.   begin
  308.     FFocusedButton.TimeBtnState := FFocusedButton.TimeBtnState - [tbFocusRect];
  309.     FFocusedButton := Btn;
  310.     if (GetFocus = Handle) then 
  311.     begin
  312.        FFocusedButton.TimeBtnState := FFocusedButton.TimeBtnState + [tbFocusRect];
  313.        Invalidate;
  314.     end;
  315.   end;
  316. end;
  317.  
  318. procedure TSpinButton.WMGetDlgCode(var Message: TWMGetDlgCode);
  319. begin
  320.   Message.Result := DLGC_WANTARROWS;
  321. end;
  322.  
  323. procedure TSpinButton.Loaded;
  324. var
  325.   W, H: Integer;
  326. begin
  327.   inherited Loaded;
  328.   W := Width;
  329.   H := Height;
  330.   AdjustSize (W, H);
  331.   if (W <> Width) or (H <> Height) then
  332.     inherited SetBounds (Left, Top, W, H);
  333. end;
  334.  
  335. function TSpinButton.GetUpGlyph: TBitmap;
  336. begin
  337.   Result := FUpButton.Glyph;
  338. end;
  339.  
  340. procedure TSpinButton.SetUpGlyph(Value: TBitmap);
  341. begin
  342.   if Value <> nil then
  343.     FUpButton.Glyph := Value
  344.   else
  345.   begin
  346.     FUpButton.Glyph.Handle := LoadBitmap(HInstance, 'SpinUp');
  347.     FUpButton.NumGlyphs := 1;
  348.     FUpButton.Invalidate;
  349.   end;
  350. end;
  351.  
  352. function TSpinButton.GetUpNumGlyphs: TNumGlyphs;
  353. begin
  354.   Result := FUpButton.NumGlyphs;
  355. end;
  356.  
  357. procedure TSpinButton.SetUpNumGlyphs(Value: TNumGlyphs);
  358. begin
  359.   FUpButton.NumGlyphs := Value;
  360. end;
  361.  
  362. function TSpinButton.GetDownGlyph: TBitmap;
  363. begin
  364.   Result := FDownButton.Glyph;
  365. end;
  366.  
  367. procedure TSpinButton.SetDownGlyph(Value: TBitmap);
  368. begin
  369.   if Value <> nil then
  370.     FDownButton.Glyph := Value
  371.   else
  372.   begin
  373.     FDownButton.Glyph.Handle := LoadBitmap(HInstance, 'SpinDown');
  374.     FUpButton.NumGlyphs := 1;
  375.     FDownButton.Invalidate;
  376.   end;
  377. end;
  378.  
  379. function TSpinButton.GetDownNumGlyphs: TNumGlyphs;
  380. begin
  381.   Result := FDownButton.NumGlyphs;
  382. end;
  383.  
  384. procedure TSpinButton.SetDownNumGlyphs(Value: TNumGlyphs);
  385. begin
  386.   FDownButton.NumGlyphs := Value;
  387. end;
  388.  
  389. { TSpinEdit }
  390.  
  391. constructor TSpinEdit.Create(AOwner: TComponent);
  392. begin
  393.   inherited Create(AOwner);
  394.   FButton := TSpinButton.Create (Self);
  395.   FButton.Width := 15;
  396.   FButton.Height := 17;
  397.   FButton.Visible := True;  
  398.   FButton.Parent := Self;
  399.   FButton.FocusControl := Self;
  400.   FButton.OnUpClick := UpClick;
  401.   FButton.OnDownClick := DownClick;
  402.   Text := '0';
  403.   ControlStyle := ControlStyle - [csSetCaption];
  404.   FIncrement := 1;
  405.   FEditorEnabled := True;
  406. end;
  407.  
  408. destructor TSpinEdit.Destroy;
  409. begin
  410.   FButton := nil;
  411.   inherited Destroy;
  412. end;
  413.  
  414. procedure TSpinEdit.GetChildren(Proc: TGetChildProc; Root: TComponent);
  415. begin
  416. end;
  417.  
  418. procedure TSpinEdit.KeyDown(var Key: Word; Shift: TShiftState);
  419. begin
  420.   if Key = VK_UP then UpClick (Self)
  421.   else if Key = VK_DOWN then DownClick (Self);
  422.   inherited KeyDown(Key, Shift);
  423. end;
  424.  
  425. procedure TSpinEdit.KeyPress(var Key: Char);
  426. begin
  427.   if not IsValidChar(Key) then
  428.   begin
  429.     Key := #0;
  430.     MessageBeep(0)
  431.   end;
  432.   if Key <> #0 then inherited KeyPress(Key);
  433. end;
  434.  
  435. function TSpinEdit.IsValidChar(Key: Char): Boolean;
  436. begin
  437.   Result := (Key in [DecimalSeparator, '+', '-', '0'..'9']) or
  438.     ((Key < #32) and (Key <> Chr(VK_RETURN)));
  439.   if not FEditorEnabled and Result and ((Key >= #32) or
  440.       (Key = Char(VK_BACK)) or (Key = Char(VK_DELETE))) then
  441.     Result := False;
  442. end;
  443.  
  444. procedure TSpinEdit.CreateParams(var Params: TCreateParams);
  445. begin
  446.   inherited CreateParams(Params);
  447. {  Params.Style := Params.Style and not WS_BORDER;  }
  448.   Params.Style := Params.Style or ES_MULTILINE or WS_CLIPCHILDREN;
  449. end;
  450.  
  451. procedure TSpinEdit.CreateWnd;
  452. begin
  453.   inherited CreateWnd;
  454.   SetEditRect;
  455. end;
  456.  
  457. procedure TSpinEdit.SetEditRect;
  458. var
  459.   Loc: TRect;
  460. begin
  461.   SendMessage(Handle, EM_GETRECT, 0, LongInt(@Loc));
  462.   Loc.Bottom := ClientHeight + 1;  {+1 is workaround for windows paint bug}
  463.   Loc.Right := ClientWidth - FButton.Width - 2;
  464.   Loc.Top := 0;  
  465.   Loc.Left := 0;  
  466.   SendMessage(Handle, EM_SETRECTNP, 0, LongInt(@Loc));
  467.   SendMessage(Handle, EM_GETRECT, 0, LongInt(@Loc));  {debug}
  468. end;
  469.  
  470. procedure TSpinEdit.WMSize(var Message: TWMSize);
  471. var
  472.   MinHeight: Integer;
  473. begin
  474.   inherited;
  475.   MinHeight := GetMinHeight;
  476.     { text edit bug: if size to less than minheight, then edit ctrl does
  477.       not display the text }
  478.   if Height < MinHeight then   
  479.     Height := MinHeight
  480.   else if FButton <> nil then
  481.   begin
  482.     if NewStyleControls and Ctl3D then
  483.       FButton.SetBounds(Width - FButton.Width - 5, 0, FButton.Width, Height - 5)
  484.     else FButton.SetBounds (Width - FButton.Width, 1, FButton.Width, Height - 3);
  485.     SetEditRect;
  486.   end;
  487. end;
  488.  
  489. function TSpinEdit.GetMinHeight: Integer;
  490. var
  491.   DC: HDC;
  492.   SaveFont: HFont;
  493.   I: Integer;
  494.   SysMetrics, Metrics: TTextMetric;
  495. begin
  496.   DC := GetDC(0);
  497.   GetTextMetrics(DC, SysMetrics);
  498.   SaveFont := SelectObject(DC, Font.Handle);
  499.   GetTextMetrics(DC, Metrics);
  500.   SelectObject(DC, SaveFont);
  501.   ReleaseDC(0, DC);
  502.   I := SysMetrics.tmHeight;
  503.   if I > Metrics.tmHeight then I := Metrics.tmHeight;
  504.   Result := Metrics.tmHeight + I div 4 + GetSystemMetrics(SM_CYBORDER) * 4 + 2;
  505. end;
  506.  
  507. procedure TSpinEdit.UpClick (Sender: TObject);
  508. begin
  509.   if ReadOnly then MessageBeep(0)
  510.   else Value := Value + FIncrement;
  511. end;
  512.  
  513. procedure TSpinEdit.DownClick (Sender: TObject);
  514. begin
  515.   if ReadOnly then MessageBeep(0)
  516.   else Value := Value - FIncrement;
  517. end;
  518.  
  519. procedure TSpinEdit.WMPaste(var Message: TWMPaste);   
  520. begin
  521.   if not FEditorEnabled or ReadOnly then Exit;
  522.   inherited;
  523. end;
  524.  
  525. procedure TSpinEdit.WMCut(var Message: TWMPaste);   
  526. begin
  527.   if not FEditorEnabled or ReadOnly then Exit;
  528.   inherited;
  529. end;
  530.  
  531. procedure TSpinEdit.CMExit(var Message: TCMExit);
  532. begin
  533.   inherited;
  534.   if CheckValue (Value) <> Value then
  535.     SetValue (Value);
  536. end;
  537.  
  538. function TSpinEdit.GetValue: LongInt;
  539. begin
  540.   try
  541.     Result := StrToInt (Text);
  542.   except
  543.     Result := FMinValue;
  544.   end;
  545. end;
  546.  
  547. procedure TSpinEdit.SetValue (NewValue: LongInt);
  548. begin
  549.   Text := IntToStr (CheckValue (NewValue));
  550. end;
  551.  
  552. function TSpinEdit.CheckValue (NewValue: LongInt): LongInt;
  553. begin
  554.   Result := NewValue;
  555.   if (FMaxValue <> FMinValue) then
  556.   begin
  557.     if NewValue < FMinValue then
  558.       Result := FMinValue
  559.     else if NewValue > FMaxValue then
  560.       Result := FMaxValue;
  561.   end;
  562. end;
  563.  
  564. procedure TSpinEdit.CMEnter(var Message: TCMGotFocus);
  565. begin
  566.   if AutoSelect and not (csLButtonDown in ControlState) then
  567.     SelectAll;
  568.   inherited;
  569. end;
  570.  
  571. {TTimerSpeedButton}
  572.  
  573. destructor TTimerSpeedButton.Destroy;
  574. begin
  575.   if FRepeatTimer <> nil then
  576.     FRepeatTimer.Free;
  577.   inherited Destroy;
  578. end;
  579.  
  580. procedure TTimerSpeedButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
  581.   X, Y: Integer);
  582. begin
  583.   inherited MouseDown (Button, Shift, X, Y);
  584.   if tbAllowTimer in FTimeBtnState then
  585.   begin
  586.     if FRepeatTimer = nil then
  587.       FRepeatTimer := TTimer.Create(Self);
  588.  
  589.     FRepeatTimer.OnTimer := TimerExpired;
  590.     FRepeatTimer.Interval := InitRepeatPause;
  591.     FRepeatTimer.Enabled  := True;
  592.   end;
  593. end;
  594.  
  595. procedure TTimerSpeedButton.MouseUp(Button: TMouseButton; Shift: TShiftState;
  596.                                   X, Y: Integer);
  597. begin
  598.   inherited MouseUp (Button, Shift, X, Y);
  599.   if FRepeatTimer <> nil then
  600.     FRepeatTimer.Enabled  := False;
  601. end;
  602.  
  603. procedure TTimerSpeedButton.TimerExpired(Sender: TObject);
  604. begin
  605.   FRepeatTimer.Interval := RepeatPause;
  606.   if (FState = bsDown) and MouseCapture then
  607.   begin
  608.     try
  609.       Click;
  610.     except
  611.       FRepeatTimer.Enabled := False;
  612.       raise;
  613.     end;
  614.   end;
  615. end;
  616.  
  617. procedure TTimerSpeedButton.Paint;
  618. var
  619.   R: TRect;
  620. begin
  621.   inherited Paint;
  622.   if tbFocusRect in FTimeBtnState then
  623.   begin
  624.     R := Bounds(0, 0, Width, Height);
  625.     InflateRect(R, -3, -3);
  626.     if FState = bsDown then
  627.       OffsetRect(R, 1, 1);
  628.     DrawFocusRect(Canvas.Handle, R);
  629.   end;
  630. end;
  631.  
  632. end.
  633.